/******************************************************************************\
    Common.cpp contains many different features.
    It's used for acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#include ".\Common.h"
#include <Common\String.h>
#include <Common\Memory.hpp>
#include <Common\StdFile.hpp>
#include ".\ConfigFile.h"
using namespace std;

string ExeName;
unsigned long MainThreadId;

cLog Log;

cCriticalData< bool > IsRemoteProxyUsed( false );
cCriticalData< string > RemoteProxyHost( "" );
cCriticalData< unsigned short > RemoteProxyPort( 0 );
cCriticalData< unsigned short > LocalProxyPort( 0 );
cCriticalData< string > RemoteProxyLogin( "" );
cCriticalData< string > RemoteProxyPassword( "" );

cSubmitQueue SubmitQueue;

nsClientDataBase::cClientDataBase ClientDataBase;
nsContestantDataBase::cContestantDataBase ContestantDataBase;
nsContestantCookieDataBase::cContestantCookieDataBase ContestantCookieDataBase;
nsPluginDataBase::cPluginDataBase PluginDataBase;
nsContestDataBase::cContestDataBase ContestDataBase;
nsProblemDataBase::cProblemDataBase ProblemDataBase;
nsContestProblemDataBase::cContestProblemDataBase ContestProblemDataBase;
nsContestContestantDataBase::cContestContestantDataBase ContestContestantDataBase;
nsContestContestantProblemDataBase::cContestContestantProblemDataBase ContestContestantProblemDataBase;
nsLanguageDataBase::cLanguageDataBase LanguageDataBase;
cDataFile ContestContestantProblemDataFile;

bool GetVariable( const cFormat variable, const std::string &name, unsigned long &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	return variable_iterator->second.ParseUnsignedLong( value );
}

bool GetVariable( const cFormat variable, const std::string &name, unsigned long &value, bool &is_empty )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	is_empty = true;
	if( variable_iterator->second.IsValue() && variable_iterator->second.AsString().length() == 0 )
		return true;
	is_empty = false;
	return variable_iterator->second.ParseUnsignedLong( value );
}

bool GetVariable( const cFormat variable, const std::string &name, long &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	return variable_iterator->second.ParseLong( value );
}

bool GetVariable( const cFormat variable, const std::string &name, long &value, bool &is_empty )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	is_empty = true;
	if( variable_iterator->second.IsValue() && variable_iterator->second.AsString().length() == 0 )
		return true;
	is_empty = false;
	return variable_iterator->second.ParseLong( value );
}

bool GetVariable( const cFormat variable, const std::string &name, unsigned short &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	return variable_iterator->second.ParseUnsignedShort( value );
}

bool GetVariable( const cFormat variable, const std::string &name, unsigned short &value, bool &is_empty )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	is_empty = true;
	if( variable_iterator->second.IsValue() && variable_iterator->second.AsString().length() == 0 )
		return true;
	is_empty = false;
	return variable_iterator->second.ParseUnsignedShort( value );
}

bool GetVariable( const cFormat variable, const std::string &name, std::string &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	return variable_iterator->second.ParseString( value );
}

bool GetVariable( const cFormat variable, const std::string &name, bool &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	value = variable_iterator != variable.End();
	return true;
}

bool GetVariable( const cFormat variable, const std::string &name, std::vector< unsigned long > &value )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	if( variable_iterator->second.IsValue() )
	{
		value.resize( 1 );
		return variable_iterator->second.ParseUnsignedLong( value.front() );
	}
	else if( variable_iterator->second.IsArray() )
	{
		value.resize( variable_iterator->second.Size() );
		for( int i = 0; i < ( int )variable_iterator->second.Size(); ++i )
		{
			if( !variable_iterator->second[ i ].ParseUnsignedLong( value[ i ] ) )
				return false;
		}
		return true;
	}
	else
		return false;
}

bool GetVariable( const cFormat variable, const std::string &name, std::string &file_name, std::string &data )
{
	if( !variable.IsList() )
		return false;
	cFormat::const_iterator variable_iterator = variable.Find( name );
	if( variable_iterator == variable.End() )
		return false;
	if( !variable_iterator->second.IsList() )
		return false;
	if( !variable_iterator->second[ "FileName" ].ParseString( file_name ) )
		return false;
	if( !variable_iterator->second[ "Data" ].ParseString( data ) )
		return false;
	return true;
}

bool _DeleteContestContestantProblem( unsigned long contest_contestant_problem_id )
{
	cLocker locker( *ContestContestantProblemDataBase );
	if( ContestContestantProblemDataBase->FindByKey( contest_contestant_problem_id ) == ContestContestantProblemDataBase->EndByKey() )
		return false;
	if( !ContestContestantProblemDataBase->Delete( contest_contestant_problem_id ) )
		return false;
	return true;
}

bool DeleteContestContestantProblem( unsigned long contest_contestant_problem_id )
{
	if( !_DeleteContestContestantProblem( contest_contestant_problem_id ) )
		return false;
	ContestContestantProblemDataBase->Flush();
	return true;
}

bool _DeleteContestContestant( unsigned long contest_contestant_id )
{
	cLocker locker( *ContestContestantDataBase );
	if( ContestContestantDataBase->FindByKey( contest_contestant_id ) == ContestContestantDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestContestantProblemDataBase );
		for( nsContestContestantProblemDataBase::ContestContestantIdIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->LowerBoundByContestContestantId( contest_contestant_id ), contest_contestant_problem_end = ContestContestantProblemDataBase->UpperBoundByContestContestantId( contest_contestant_id ); contest_contestant_problem_iterator != contest_contestant_problem_end; )
		{
			if( !_DeleteContestContestantProblem( contest_contestant_problem_iterator++->Key ) )
				return false;
		}
	}
	if( !ContestContestantDataBase->Delete( contest_contestant_id ) )
		return false;
	return true;
}

bool DeleteContestContestant( unsigned long contest_contestant_id )
{
	if( !_DeleteContestContestant( contest_contestant_id ) )
		return false;
	ContestContestantDataBase->Flush();
	return true;
}

bool _DeleteContestProblem( unsigned long contest_problem_id )
{
	cLocker locker( *ContestProblemDataBase );
	if( ContestProblemDataBase->FindByKey( contest_problem_id ) == ContestProblemDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestContestantProblemDataBase );
		for( nsContestContestantProblemDataBase::ContestProblemIdIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->LowerBoundByContestProblemId( contest_problem_id ), contest_contestant_problem_end = ContestContestantProblemDataBase->UpperBoundByContestProblemId( contest_problem_id ); contest_contestant_problem_iterator != contest_contestant_problem_end; )
		{
			if( !_DeleteContestContestantProblem( contest_contestant_problem_iterator++->Key ) )
				return false;
		}
	}
	if( !ContestProblemDataBase->Delete( contest_problem_id ) )
		return false;
	return true;
}

bool DeleteContestProblem( unsigned long contest_problem_id )
{
	if( !_DeleteContestProblem( contest_problem_id ) )
		return false;
	ContestProblemDataBase->Flush();
	return true;
}

bool _DeleteContestant( unsigned long contestant_id )
{
	cLocker locker( *ContestantDataBase );
	if( ContestantDataBase->FindByKey( contestant_id ) == ContestantDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestContestantDataBase );
		for( nsContestContestantDataBase::ContestantIdIterator contest_contestant_iterator = ContestContestantDataBase->LowerBoundByContestantId( contestant_id ), contest_contestant_end = ContestContestantDataBase->UpperBoundByContestantId( contestant_id ); contest_contestant_iterator != contest_contestant_end; )
		{
			if( !_DeleteContestContestant( contest_contestant_iterator++->Key ) )
				return false;			
		}
	}
	if( !ContestantDataBase->Delete( contestant_id ) )
		return false;
	return true;
}

bool DeleteContestant( unsigned long contestant_id )
{
	if( !_DeleteContestant( contestant_id ) )
		return false;
	ContestantDataBase->Flush();
	return true;
}

bool _DeleteProblem( unsigned long problem_id )
{
	cLocker locker( *ProblemDataBase );
	if( ProblemDataBase->FindByKey( problem_id ) == ProblemDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestProblemDataBase );
		for( nsContestProblemDataBase::ProblemIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByProblemId( problem_id ), contest_problem_end = ContestProblemDataBase->UpperBoundByProblemId( problem_id ); contest_problem_iterator != contest_problem_end; )
		{
			if( !_DeleteContestProblem( contest_problem_iterator++->Key ) )
				return false;
		}
	}
	if( !ProblemDataBase->Delete( problem_id ) )
		return false;
	return true;
}

bool DeleteProblem( unsigned long problem_id )
{
	if( !_DeleteProblem( problem_id ) )
		return false;
	ProblemDataBase->Flush();
	return true;
}

bool _DeleteLanguage( unsigned long language_id )
{
	cLocker locker( *LanguageDataBase );
	if( LanguageDataBase->FindByKey( language_id ) == LanguageDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestContestantProblemDataBase );
		for( nsContestContestantProblemDataBase::LanguageIdIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->LowerBoundByLanguageId( language_id ), contest_contestant_problem_end = ContestContestantProblemDataBase->UpperBoundByLanguageId( language_id ); contest_contestant_problem_iterator != contest_contestant_problem_end; )
		{
			if( !_DeleteContestContestantProblem( contest_contestant_problem_iterator++->Key ) )
				return false;
		}
	}
	if( !LanguageDataBase->Delete( language_id ) )
		return false;
	return true;
}

bool DeleteLanguage( unsigned long language_id )
{
	if( !_DeleteLanguage( language_id ) )
		return false;
	LanguageDataBase->Flush();
	return true;
}

bool _DeleteContest( unsigned long contest_id )
{
	cLocker locker( *ContestDataBase );
	if( ContestDataBase->FindByKey( contest_id ) == ContestDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *ContestContestantDataBase );
		for( nsContestContestantDataBase::ContestIdIterator contest_contestant_iterator = ContestContestantDataBase->LowerBoundByContestId( contest_id ), contest_contestant_end = ContestContestantDataBase->UpperBoundByContestId( contest_id ); contest_contestant_iterator != contest_contestant_end; )
		{
			if( !_DeleteContestContestant( contest_contestant_iterator++->Key ) )
				return false;
		}
	}
	{
		cLocker locker( *ContestProblemDataBase );
		for( nsContestProblemDataBase::ContestIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByContestId( contest_id ), contest_problem_end = ContestProblemDataBase->UpperBoundByContestId( contest_id ); contest_problem_iterator != contest_problem_end; )
		{
			if( !_DeleteContestProblem( contest_problem_iterator++->Key ) )
				return false;
		}
	}
	if( !ContestDataBase->Delete( contest_id ) )
		return false;
	return true;
}

bool DeleteContest( unsigned long contest_id )
{
	if( !_DeleteContest( contest_id ) )
		return false;
	ContestDataBase->Flush();
	return true;
}

bool _DeletePlugin( unsigned long plugin_id )
{
	cLocker locker( *PluginDataBase );
	if( PluginDataBase->FindByKey( plugin_id ) == PluginDataBase->EndByKey() )
		return false;
	{
		cLocker locker( *LanguageDataBase );
		for( nsLanguageDataBase::PluginIdIterator language_iterator = LanguageDataBase->LowerBoundByPluginId( plugin_id ), language_end = LanguageDataBase->UpperBoundByPluginId( plugin_id ); language_iterator != language_end; )
		{
			if( !_DeleteLanguage( language_iterator++->Key ) )
				return false;
		}
	}
	{
		cLocker locker( *ProblemDataBase );
		for( nsProblemDataBase::PluginIdIterator problem_iterator = ProblemDataBase->LowerBoundByPluginId( plugin_id ), problem_end = ProblemDataBase->UpperBoundByPluginId( plugin_id ); problem_iterator != problem_end; )
		{
			if( !_DeleteProblem( problem_iterator++->Key ) )
				return false;
		}
	}
	if( !PluginDataBase->Delete( plugin_id ) )
		return false;
	return true;
}

bool DeletePlugin( unsigned long plugin_id )
{
	if( !_DeletePlugin( plugin_id ) )
		return false;
	PluginDataBase->Flush();
	return true;
}

bool RefreshLanguages( unsigned long plugin_id )
{
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	nsPluginDataBase::sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return false;
	//if( !plugin_data.IsEnabled || plugin_data.Handle == NULL )
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) || plugin_data.Handle == NULL )
		return false;
	unsigned long languages_count;
	if( !plugin_data.MainProc( GET_LANGUAGES_COUNT, 0, &languages_count ) )
		return false;
	cMemory< unsigned long > language_id( languages_count );
	if( !plugin_data.MainProc( GET_LANGUAGES_IDS, 0, language_id ) )
		return false;
	{
		cLocker locker( *LanguageDataBase );
		for( unsigned long i = 0; i < languages_count; ++i )
		{
			unsigned long language_title_length;
			if( !plugin_data.MainProc( GET_LANGUAGE_TITLE_LENGTH, language_id[ i ], &language_title_length ) )
				return false;
			cMemory< char > language_title( language_title_length + 1 );
			if( !plugin_data.MainProc( GET_LANGUAGE_TITLE, language_id[ i ], language_title ) )
				return false;
			nsLanguageDataBase::sLanguageData language_data;
			if( LanguageDataBase->GetByPluginIdAndIndex( plugin_id, language_id[ i ], language_data ) )
			{
				strncpy( language_data.Title, language_title, nsLanguageDataBase::MAX_TITLE_LENGTH )[ nsLanguageDataBase::MAX_TITLE_LENGTH ] = '\0';
				if( !LanguageDataBase->Update( language_data ) )
					return false;
			}
			else
			{
				language_data.PluginId = plugin_id;
				language_data.Index = language_id[ i ];
				strncpy( language_data.Title, language_title, nsLanguageDataBase::MAX_TITLE_LENGTH )[ nsLanguageDataBase::MAX_TITLE_LENGTH ] = '\0';
				if( LanguageDataBase->Insert( language_data ) == BAD_KEY )
					return false;
			}
		}
	}
	return true;
}

bool RefreshProblems( unsigned long plugin_id )
{
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	nsPluginDataBase::sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return false;
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) || plugin_data.Handle == NULL )
		return false;
	unsigned long problems_count;
	if( !plugin_data.MainProc( GET_PROBLEMS_COUNT, 0, &problems_count ) )
		return false;
	cMemory< unsigned long > problem_id( problems_count );
	if( !plugin_data.MainProc( GET_PROBLEMS_IDS, 0, problem_id ) )
		return false;
	{
		cLocker locker( *ProblemDataBase );
		for( unsigned long i = 0; i < problems_count; ++i )
		{
			unsigned long problem_header_length;
			if( !plugin_data.MainProc( GET_PROBLEM_HEADER_LENGTH, problem_id[ i ], &problem_header_length ) )
				return false;
			cMemory< char > problem_header( problem_header_length + 1 );
			if( !plugin_data.MainProc( GET_PROBLEM_HEADER, problem_id[ i ], problem_header ) )
				return false;
			nsProblemDataBase::sProblemData problem_data;
			if( ProblemDataBase->GetByPluginIdAndIndex( plugin_id, problem_id[ i ], problem_data ) )
			{
				if( strncmp( problem_data.Header, problem_header, nsProblemDataBase::MAX_HEADER_LENGTH ) != 0 )
				{
					strncpy( problem_data.Header, problem_header, nsProblemDataBase::MAX_HEADER_LENGTH )[ nsProblemDataBase::MAX_HEADER_LENGTH ] = '\0';
					if( !ProblemDataBase->Update( problem_data ) )
						return false;
				}
			}
			else
			{
				problem_data.PluginId = plugin_id;
				problem_data.Index = problem_id[ i ];
				strncpy( problem_data.Header, problem_header, nsProblemDataBase::MAX_HEADER_LENGTH )[ nsProblemDataBase::MAX_HEADER_LENGTH ] = '\0';
				if( ProblemDataBase->Insert( problem_data ) == BAD_KEY )
					return false;
			}
		}
	}
	return true;
}

static std::map< unsigned long, cReadWriteCriticalSection > ReadWriteCriticalSection;

cReadWriteCriticalSection GetPluginCriticalSection( unsigned long plugin_id )
{
	static cCriticalSection get_critical_section;
	cLocker locker( get_critical_section );
	std::map< unsigned long, cReadWriteCriticalSection >::const_iterator read_write_critical_section_iterator = ReadWriteCriticalSection.find( plugin_id );
	if( read_write_critical_section_iterator != ReadWriteCriticalSection.end() )
		return read_write_critical_section_iterator->second;
	cReadWriteCriticalSection read_write_critical_section;
	_ASSERT( read_write_critical_section.Create() );
	ReadWriteCriticalSection.insert( make_pair( plugin_id, read_write_critical_section ) );
	return read_write_critical_section;
}

static bool _LoadPlugin( nsPluginDataBase::sPluginData &plugin_data )
{
	try
	{
		plugin_data.MainProc = ( tMainProc )GetProcAddress( plugin_data.Handle, nsPluginDataBase::MAIN_PROC_NAME );
		if( plugin_data.MainProc == NULL )
			return false;
		if( !plugin_data.MainProc( SET_PROXY_PORT, ( unsigned long )LocalProxyPort, NULL ) )
			return false;
		unsigned long variables_count;
		if( !plugin_data.MainProc( GET_VARIABLES_COUNT, 0, &variables_count ) )
			return false;
		for( unsigned long variable_id = 0; variable_id < variables_count; ++variable_id )
		{
			unsigned long variable_properties_length;
			if( !plugin_data.MainProc( GET_VARIABLE_PROPERTIES_LENGTH, variable_id, &variable_properties_length ) )
			{
				unsigned long variable_name_length;
				if( !plugin_data.MainProc( GET_VARIABLE_NAME_LENGTH, variable_id, &variable_name_length ) )
					return false;
				cMemory< char > variable_name( variable_name_length + 1 );
				if( !plugin_data.MainProc( GET_VARIABLE_NAME, variable_id, variable_name ) )
					return false;
				string variable_value = "";
				{
					cLocker locker( ConfigCriticalSection );
					if( Config[ "Plugins" ][ plugin_data.Name ][ variable_name ].IsValue() )
						variable_value = Config[ "Plugins" ][ plugin_data.Name ][ variable_name ];
				}
				if( !plugin_data.MainProc( SET_VARIABLE_VALUE, variable_id, ( void * )variable_value.c_str() ) )
					return false;
				continue;
			}
			cMemory< char > variable_properties( variable_properties_length + 1 );
			if( !plugin_data.MainProc( GET_VARIABLE_PROPERTIES, variable_id, variable_properties ) )
				return false;
			cFormat variable;
			if( !variable.CreateFromString( string( variable_properties ) ) )
				return false;
			string variable_value = "";
			{
				cLocker locker( ConfigCriticalSection );
				if( Config[ "Plugins" ][ plugin_data.Name ][ variable[ "Name" ] ].IsValue() )
					variable_value = Config[ "Plugins" ][ plugin_data.Name ][ variable[ "Name" ] ];
			}
			if( !plugin_data.MainProc( SET_VARIABLE_VALUE, variable_id, ( void * )variable_value.c_str() ) )
				return false;
		}
		return true;
	}
	catch( ... )
	{
		return false;
	}
}

bool LoadPlugin( nsPluginDataBase::sPluginData plugin_data )
{
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) )
		return true;
	vector< string > path = Split( ExeName, "\\" );
	path.back() = string( plugin_data.Name ) + ".dll";
	plugin_data.Handle = LoadLibrary( Concat( path, "\\" ).c_str() );
	if( plugin_data.Handle != NULL )
	{
		if( !_LoadPlugin( plugin_data ) )
		{
			FreeLibrary( plugin_data.Handle );
			plugin_data.Handle = NULL;
		}
	}
	if( !PluginDataBase->Update( plugin_data ) )
		return false;
	return true;
}

bool UnloadPlugin( nsPluginDataBase::sPluginData plugin_data )
{
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) )
		return true;
	if( plugin_data.Handle != NULL )
	{
		FreeLibrary( plugin_data.Handle );
		plugin_data.Handle = NULL;
	}
	if( !PluginDataBase->Update( plugin_data ) )
		return false;
	return true;
}

//bool SaveString( const cLockObject &lock_object, const char file_name[], const std::string &str, unsigned long &offset )
//{
//	cLocker locker( lock_object );
//	cStdFile file;
//	vector< string > path = Split( ExeName, "\\" );
//	path.back() = file_name;
//	if( !file.Open( Concat( path, "\\" ).c_str(), "r+b" ) &&
//		 !file.Open( Concat( path, "\\" ).c_str(), "wb" ) )
//		return false;
//	file.Seek( 0, SEEK_END );
//	offset = file.Tell();
//	if( str.length() != 0 )
//		if( file.Write( str.c_str(), str.length(), 1 ) != 1 )
//			return false;
//	return true;
//}
//
//bool LoadString( const cLockObject &lock_object, const char file_name[], unsigned long offset, unsigned long length, std::string &str )
//{
//	cLocker locker( lock_object );
//	cStdFile file;
//	vector< string > path = Split( ExeName, "\\" );
//	path.back() = file_name;
//	if( !file.Open( Concat( path, "\\" ).c_str(), "rb" ) )
//		return false;
//	if( file.Seek( ( long )offset, SEEK_SET ) != 0 )
//		return false;
//	if( length != 0 )
//	{
//		cMemory< char > buffer( length );
//		if( file.Read( buffer, length, 1 ) != 1 )
//			return false;
//		str = string( buffer, length );
//	}
//	else
//		str = "";
//	return true;
//}

bool ReadFile( const char file_name[], std::string &data )
{
	cStdFile file;
	if( !file.Open( file_name, "rb" ) )
		return false;
	data.clear();
	int ch;
	while( ( ch = file.GetChar() ) != EOF )
		data.push_back( ( char )ch );
	return true;
}

bool WriteFile( const char file_name[], const std::string &data )
{
	cStdFile file;
	if( !file.Open( file_name, "wb" ) )
		return false;
	for( int i = 0; i < ( int )data.length(); ++i )
	{
		file.PutChar( ( int )( unsigned )( unsigned char )data[ i ] );
	}
	return true;
}


//void MultiValueVariableDecode( const std::string &data, std::string &value, std::map< std::string, std::string > &sub_variable )
//{
//	vector< string > temp1 = Split( data, ";" );
//	value = ToLower( Trim( temp1.front() ) );
//	for( int i = 1; i < ( int )temp1.size(); ++i )
//	{
//		vector< string > temp2 = Split( Trim( temp1[ i ] ), "=" );
//		string name = ToLower( Trim( temp2.front() ) );
//		temp2.erase( temp2.begin() );
//		sub_variable.insert( make_pair( name, Trim( Concat( temp2, "=" ) ) ) );
//	}
//}

void MultiValueVariableDecode( const std::string &data, cFormat &variable )
{
	variable.CreateList();
	variable.Insert( "Value" );
	vector< string > temp1 = Split( data, ";" );
	if( temp1.size() < 1 )
		return;
	variable[ "Value" ] = ToLower( Trim( temp1.front() ) );
	cFormat &parameter = variable[ "Parameter" ];
	parameter.CreateList();
	for( int i = 1; i < ( int )temp1.size(); ++i )
	{
		vector< string > temp2 = Split( Trim( temp1[ i ] ), "=" );
		if( temp2.size() < 1 )
			continue;
		string name = ToLower( Trim( temp2.front() ) );
		parameter.Insert( name );
		temp2.erase( temp2.begin() );
		if( temp2.size() < 1 )
			continue;
		parameter[ name ] = Trim( Concat( temp2, "=" ) );
	}
}

std::string MakeParameters( const cFormat parameter )
{
	vector< string > result;
	for( cFormat::const_iterator parameter_iterator = parameter.Begin(); parameter_iterator != parameter.End(); ++parameter_iterator )
	{
		if( parameter_iterator->second.IsValue() )
			result.push_back( parameter_iterator->first + "=" + parameter_iterator->second.AsString() );
		else if( parameter_iterator->second.IsArray() )
			for( int i = 0; i < ( int )parameter_iterator->second.Size(); ++i )
			{
				result.push_back( parameter_iterator->first + "=" + parameter_iterator->second[ i ].AsString() );
			}
	}
	return Concat( result, "&" );
}
